/*
 * Copyright (C) 2021 Nain57
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
package com.buzbuz.smartautoclicker.database.room.dao

/**
 * Helper class to update a list in the database.
 *
 * When updating a complete list of entities in a database, you have the find which items will be added, updated or
 * removed. This class provides this information using the method [refreshUpdateValues] to parse the list, and the
 * [toBeAdded], [toBeUpdated] and [toBeRemoved] list to get the information.
 *
 * @param E type of the items in the list to be updated.
 * @param K type of the primary key of the items [E].
 * @param defaultPrimaryKey the default value for the primary key. This is the default room value for an autogenerated
 *                          primary key (ex: Long = 0L).
 * @param primaryKeySupplier provides the item primary key.
 */
internal class EntityListUpdater<E, K>(
    private val defaultPrimaryKey: K,
    private inline val primaryKeySupplier: (E) -> K,
) {

    /** The list of items to be added. */
    val toBeAdded = mutableListOf<E>()
    /** The list of items to be updated. */
    val toBeUpdated = mutableListOf<E>()
    /** The list of items to be removed. */
    val toBeRemoved = mutableListOf<E>()

    /**
     * Refresh the add, update and remove lists.
     *
     * @param oldList the list of entities currently in the database.
     * @param newList the updated list of entities to be inserted in the database.
     */
    fun refreshUpdateValues(oldList: List<E>, newList: List<E>) {
        // Clear previous use values
        toBeAdded.clear()
        toBeUpdated.clear()
        toBeRemoved.clear()

        // New items with the default primary key should be added, others should be updated.
        newList.forEach { newChild ->
            if (primaryKeySupplier(newChild) == defaultPrimaryKey) {
                toBeAdded.add(newChild)
            } else {
                toBeUpdated.add(newChild)
            }
        }

        // All items in the old list that aren't in the new one should be removed.
        toBeRemoved.addAll(oldList.filter { oldChild ->
            newList.find { newChild ->
                primaryKeySupplier(oldChild) == primaryKeySupplier(newChild)
            } == null
        })
    }
}
